package br.gov.cemaden.cliente.inmet;

import br.gov.cemaden.cliente.inmet.exception.NoDataException;
import br.gov.cemaden.library.dao.MunicipioMonitoradoRepository;
import br.gov.cemaden.library.model.alerta.Agencia;
import br.gov.cemaden.library.model.Municipio;
import br.gov.cemaden.library.model.previsao.AquisicaoTempo;
import br.gov.cemaden.library.model.previsao.PrevisaoTempo;
import br.gov.cemaden.library.dao.MunicipioRepository;
import br.gov.cemaden.library.model.MunicipioMonitorado;
import br.gov.cemaden.library.repository.alerta.AgenciaRepository;
import br.gov.cemaden.library.util.Util;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Queue;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

/**
 *
 *
 */
public class ClienteInmet 
{
        
    public static void main( String[] args )
    {
        
        Logger logger = LoggerFactory.getLogger(ClienteInmet.class);
        Marker FATAL = MarkerFactory.getMarker("FINAL");
                
        Properties properties = new Properties();
        
        if(args.length > 1){
            Path file = Paths.get(args[1]);
            if(Files.notExists(file)){
                logger.error(FATAL, "The specified file doesn't exists", file.toAbsolutePath());
                System.exit(-1);
            }
            try {
                properties.load(new FileInputStream(file.toFile()));
            } catch (IOException ex) {
                logger.error(FATAL, "Error when loading properties from file " + file.toAbsolutePath(), ex);
                System.exit(-1);
            }
        }        
        
        ClienteInmet a = new ClienteInmet();
        a.processData(properties);
    }
    
    public void processData(Properties properties){            
        
        Logger logger = LoggerFactory.getLogger(ClienteInmet.class);
        
        String webservice = properties.getProperty("webservice.url", 
                "http://www.inmet.gov.br/portal/index.php?r=prevmet/previsaoWebservice/getJsonPrevisaoDiariaPorCidade&code=");
        
        EntityManagerFactory entitymf = Persistence.createEntityManagerFactory("cemaden");
        EntityManager em = entitymf.createEntityManager();
        
        MunicipioMonitoradoRepository repository = new MunicipioMonitoradoRepository(em);        
        
        Queue<MunicipioMonitorado> municipios = new LinkedList<MunicipioMonitorado>();
        municipios.addAll(repository.list('S'));                                              
        
        MunicipioRepository municipioRepository = new MunicipioRepository(em);
        
        AgenciaRepository agencias = new AgenciaRepository(em);
        Agencia agencia = agencias.find("Inmet");
        
        if(agencia == null)
            throw new RuntimeException("There is none agency called Inmet on the database");  
        
        AquisicaoTempo aquisicao = new AquisicaoTempo();
        try {
            aquisicao.setAquisicao(Util.parseDateFromLocalToGMT(new Date(System.currentTimeMillis())));
        } catch (java.text.ParseException ex) {
            logger.error("Error when trying to parse date from local to GMT", ex);
        }
        aquisicao.setAgencia(agencia);
        aquisicao = aquisicao.save(em);
        
        while(!municipios.isEmpty()) {
            
            MunicipioMonitorado m = municipios.remove();
            Municipio municipio = municipioRepository.getByGeoCodigo(m.getGeocodigo());            
            String address = String.format("%s%d", webservice, municipio.getCodIBGE());
            
            URL url;
            BufferedReader reader = null;
            
            try {                                
                
                url = new URL(address);                                                             
                                
                reader = new BufferedReader(new InputStreamReader(url.openStream()));                                
                
                JSONReader json = new JSONReader();
                List<PrevisaoTempo> previsoes = json.getPrevisoes(reader, municipio);                                
                
                for (PrevisaoTempo previsao : previsoes) {
                    previsao.setAquisicao(aquisicao);
                    previsao.save(em);
                }
                
            } 
            catch (FileNotFoundException ex) {
                logger.error(String.format("A URL %s não foi encontrada.", address), ex);
                municipios.add(m);
            } 
            catch (IOException ex) {
                logger.error(String.format("Erro ao tentar gerar arquivo para o municipio %s (%s) baseado na URL %s", 
                        municipio.getCidade(), municipio.getUf(), address), ex);
                municipios.add(m);
            } 
            catch (org.json.simple.parser.ParseException ex) {
                logger.error(String.format("Erro ao tentar fazer o parse do objeto JSON para o municipio  %s (%s)", 
                        municipio.getCidade(), municipio.getUf()), ex);
                municipios.add(m);
            } 
            catch (java.text.ParseException ex) {
                logger.error("Error when trying to parse Date do GMT format.", ex);
            } 
            catch (NoDataException ex) {
                logger.info(String.format("Não há dados novos para o município %s (%s). Ele será inserido novamente na fila de processos", 
                        municipio.getCidade(), municipio.getUf()), ex);
                municipios.add(m);
            }
            finally{
                try {
                    if(reader != null){
                        reader.close();
                    }
                } catch (IOException ex) {
                    logger.error("Error when trying to close BufferedReader resource.", ex);
                }
            }
        }             
    }
}
